package org.jxkj.client;

import com.alibaba.fastjson.JSON;
import com.ybsoftware.DNAVal;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.jxkj.dto.PointDataDTO;
import org.jxkj.dto.PointRetDTO;
import org.jxkj.dto.PointsReqResDTO;
import org.jxkj.utils.HttpClientUtils;
import org.jxkj.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * NodeJs服务的客户端
 */
public class NodeJsClient {

    private static Logger LOG = LoggerFactory.getLogger(NodeJsClient.class);

    private static final String GET = "GET";

    private static final String POST = "POST";

    public static String IP;

    public static int R_PORT;

    public static int W_PORT;

    /**
     * 获取单个测点原始值（无补点）
     * @param pointCode
     * @param startTime
     * @param endTime
     * @return
     */
    public static List<PointDataDTO> getPointValRaw(String pointCode, int startTime, int endTime) {
        String url = "http://" + IP + ":" + R_PORT + "/getPointsValRaw";
        Map<String, String> params = new HashMap<>(3);
        params.put("pointId", pointCode);
        params.put("start", String.valueOf(startTime));
        params.put("end", String.valueOf(endTime));
        try {
            logGetDataRequest(GET, url, JSON.toJSONString(params));
            String content = HttpClientUtils.get(url, params);
            logGetDataResponse(content);
            return returnPointDataList(content, pointCode);
        } catch (Exception e) {
            logHttpError(url, JSON.toJSONString(params), e);
            return new ArrayList<>(0);
        }
    }

    /**
     * 获取单个测点的快照数据（有补点）
     *
     * @param pointCode 测点编号
     * @param startTime 开始时间（单位：秒）
     * @param endTime   结束时间（单位：秒）
     * @return 采集的测点数据
     */
    public static List<PointDataDTO> getPointValSnap(String pointCode, int startTime, int endTime) {
        String url = "http://" + IP + ":" + R_PORT + "/getPointsValSnap";
        Map<String, String> params = new HashMap<>(3);
        params.put("pointId", pointCode);
        params.put("start", String.valueOf(startTime));
        params.put("end", String.valueOf(endTime));
        try {
            logGetDataRequest(GET, url, JSON.toJSONString(params));
            String content = HttpClientUtils.get(url, params);
            logGetDataResponse(content);
            return returnPointDataList(content, pointCode);
        } catch (Exception e) {
            logHttpError(url, JSON.toJSONString(params), e);
            return new ArrayList<>(0);
        }
    }

    /**
     * 写入测点数据
     *
     * @param pointsReqResDTO
     */
    public static void write(PointsReqResDTO pointsReqResDTO) {
        if (pointsReqResDTO == null || MapUtils.isEmpty(pointsReqResDTO.getData())) {
            return;
        }
        processDataType(pointsReqResDTO);
        String url = "http://" + IP + ":" + W_PORT + "/saveData";
        try {
            String body = JSON.toJSONString(pointsReqResDTO);
            logWriteDataRequest(POST, url, body);
            String content = HttpClientUtils.jsonPost(url, body);
            logWriteDataResponse(content);
        } catch (Exception e) {
            logHttpError(url, JSON.toJSONString(pointsReqResDTO), e);
        }
    }

    private static void processDataType(PointsReqResDTO pointsReqResDTO) {
        Map<String, List<List<Object>>> map = pointsReqResDTO.getData();
        Map<String, List<List<Object>>> mapNew = new HashMap<>();

        map.forEach((key, value) -> {
            List<List<Object>> listNew = new ArrayList<>(value.size());
            for (List<Object> element : value) {
                Object t = element.get(0);
                Object v = element.get(1);
                List<Object> elementNew = new ArrayList<>(2);
                if (t instanceof String) {
                    elementNew.add(Integer.parseInt((String) t));
                } else {
                    elementNew.add(t);
                }
                if (v instanceof String && !((String) v).startsWith("COMB:")) {
                    elementNew.add(Double.parseDouble((String) v));
                } else {
                    elementNew.add(v);
                }
                listNew.add(elementNew);
            }
            mapNew.put(key, listNew);
        });

        pointsReqResDTO.setData(mapNew);
    }

    /**
     * 返回测点数据
     *
     * @param content
     * @param pointCode
     * @return
     */
    private static List<PointDataDTO> returnPointDataList(String content, String pointCode) {
        if (StringUtils.isBlank(content)) {
            return new ArrayList<>(0);
        }
        PointRetDTO retDTO = JSON.parseObject(content, PointRetDTO.class);
        if (retDTO.getData() == null || retDTO.getData().get(pointCode).equals("GetHistRaw:null")) {
            return new ArrayList<>(0);
        }
        List<PointDataDTO> ret = new ArrayList<>();
        PointsReqResDTO responseDTO = JSON.parseObject(content, PointsReqResDTO.class);
        Map<String, List<List<Object>>> dataMap = responseDTO.getData();
        List<List<Object>> valueList = dataMap.get(pointCode);
        if (CollectionUtils.isNotEmpty(valueList)) {
            // 用treeMap去重和排序
            Map<Integer, Double> treeMap = new TreeMap<>();
            for (List<Object> element : valueList) {
                treeMap.put(Integer.parseInt(StringUtils.valueOf(element.get(0))), Double.parseDouble(StringUtils.valueOf(element.get(1))));
            }
            treeMap.forEach((t, v) -> {
                PointDataDTO pointDataDTO = new PointDataDTO();
                pointDataDTO.setTime(t);
                pointDataDTO.setValue(v);
                ret.add(pointDataDTO);
            });
        }
        return ret;
    }


    /**
     * 打印请求日志
     *
     * @param url
     * @param params
     */
    private static void logGetDataRequest(String method, String url, String params) {
        LOG.info("发送Http请求. method={}, url={}, params={}", method, url, params);
    }

    /**
     * 打印请求日志
     *
     * @param url
     * @param body
     */
    private static void logWriteDataRequest(String method, String url, String body) {
        LOG.info("发送Http请求. method={}, url={}", method, url);
        LOG.debug("发送Http请求. method={}, url={}, body = {}", method, url, body);
    }

    /**
     * 打印响应结果
     *
     * @param response
     */
    private static void logGetDataResponse(String response) {
        LOG.debug("获取Http响应结果. response={}", response);
    }

    /**
     * 打印响应结果
     *
     * @param response
     */
    private static void logWriteDataResponse(String response) {
        LOG.info("获取Http响应结果. response={}", response);
    }

    /**
     * 打印Http错误日志
     *
     * @param url
     * @param params
     * @param e
     */
    private static void logHttpError(String url, String params, Exception e) {
        LOG.error("Http请求发生异常. url={}, params={}", url, params);
        LOG.error("", e);
    }

    /**
     * 对象转换
     * @param list
     * @return
     */
    public static List<PointDataDTO> toPointDataDTOList(DNAVal[] list) {
        if (ArrayUtils.isEmpty(list)) {
            return new ArrayList<>(0);
        }
        List<PointDataDTO> result = new ArrayList<>(list.length);
        for (DNAVal dnaVal : list) {
            PointDataDTO dto = new PointDataDTO();
            dto.setTime(dnaVal.Time);
            dto.setValue(dnaVal.DValue);
            dto.setStatus(dnaVal.Status);
            result.add(dto);
        }
        return result;
    }

    /**
     * 对象转换
     * @param list
     * @return
     */
    public static DNAVal[] toDNAValArray(List<PointDataDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return new DNAVal[0];
        }
        DNAVal[] array = new DNAVal[list.size()];
        for (int i = 0; i < list.size(); i++) {
            DNAVal dnaVal = new DNAVal();
            dnaVal.Time = list.get(i).getTime();
            dnaVal.DValue = list.get(i).getValue();
            dnaVal.Status = list.get(i).getStatus();
            array[i] = dnaVal;
        }
        return array;
    }

}
